home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 05 - 1989 / 05.01 Jan 89 / forth stuff / Trap Compiler < prev   
Encoding:
Text File  |  1988-11-11  |  18.0 KB  |  656 lines  |  [TEXT/MACH]

  1. \ Trap compiler.  See the end of this file for examples and
  2. \ instructions.  This utility allows you to define your own
  3. \ trap "glue."   Thus as new system traps become available, you
  4. \ you will be able to define their high-level interface
  5. \ symbolically (without using assembly language).  It will also
  6. \ allow you to define a substitute syntax to the CALL interface,
  7. \ in case you need to modify (fix?) one of the existing traps.
  8. \ Note that in the latter case, you do not actually change the
  9. \ existing CALL, you simply define a new syntax which can be used
  10. \ in place of the CALL sequence.  This utility is perhaps a bit
  11. \ of "overkill," but it does illustrate rather complex parsing
  12. \ and the tools presented here could be used to extended the Mach
  13. \ compiler or assembler into new areas.  Waymen @ PASC
  14.  
  15. \ Copyright 1988  Palo Alto Shipping Company
  16. \  All Rights Reserved
  17.  
  18. \ Source format tabs = 4.
  19.  
  20. \ Compiles to about 2600 bytes of object code.
  21. \ One might wonder whether it makes good sense to include a
  22. \ 2K utility in an application when all you need is a few
  23. \ trap calls (but, see my comments below).  However, for casual
  24. \ use you might consider putting this code in your workspace,
  25. \ along with your commonly used constants, mach words, and
  26. \ other compiler utilities (that way they will always be
  27. \ available during your "experimental" sessions).  If you are
  28. \ working on a serious application, I would suggest the following
  29. \ approach.  Place all variables, mach words, and compiler
  30. \ utilities (such as this trap compiler) in a separate segment
  31. \ and when you finish your application use ResEdit to remove
  32. \ that very same segment from your finished application.
  33. \ This will work because mach words, variables, and compiler
  34. \ utilities (such as this trap compiler) do NOT need to be in
  35. \ memory during the execution of the code which they produce.
  36. \ Generally speaking, any word which only produces in-line code,
  37. \ most immediate words, or any child word which does not
  38. \ reference its parent at run-time can safely be removed from
  39. \ a finished application.  If you are really concerned about
  40. \ making the smallest possible applications, then this is a
  41. \ technique which you should always use (as a final step, when
  42. \ you are completely finished with your program).  If it seems
  43. \ risky to remove a segment from a finished application, just
  44. \ remember that there is NO WAY you can run code in another
  45. \ segment if that segment has NO jump-table entries (i.e. if
  46. \ you can't get to the code, why include it in your application?)
  47. \ Mach words, variables, and (most) compiler words don't use or
  48. \ create jump-table entries.  This same principle is why you
  49. \ never have to mark mach words or variables as GLOBAL (there
  50. \ is one exception, if you write a CODE word which explicitly
  51. \ states  "JSR <mach word>" or "LEA <mach word>" then the
  52. \ defined instance of that <mach word> must be in memory at
  53. \ run-time.  Thus if <mach word> exists in another segment, it
  54. \ will need to be marked GLOBAL (however, it's always ok to
  55. \ say LEA <variable> or MOVE.L <variable>, thus variables "never"
  56. \ need to be marked as GLOBAL).
  57.  
  58.  
  59. ONLY MAC ALSO ASSEMBLER ALSO FORTH DEFINITIONS
  60. DECIMAL
  61.  
  62. 0    CONSTANT FALSE
  63. -1    CONSTANT TRUE
  64. 32    CONSTANT BL
  65.  
  66. \ Effective address modes
  67. 1    CONSTANT An        \ address register direct
  68. 0    CONSTANT Dn        \ data register direct
  69.  
  70. \ Bit masks for MOVE <Src>,<Dst> instruction
  71. %1111000000111111    CONSTANT DstMask
  72. %1111111111000000    CONSTANT SrcMask
  73.  
  74. \ Utility to allow "fetching" of last compiled instruction.
  75. : AsmWord  ( n -- )
  76. \ Backup  n  bytes and get the 16-bit value compiled at that offset.
  77. \ Compile the value as a LITERAL.
  78.     ALLOT  HERE W@  [COMPILE] LITERAL ;
  79.  
  80. : AsmWord2  ( -- )
  81.     -2 AsmWord ;
  82.  
  83. : AsmWord4  ( -- )
  84.     -4 AsmWord ;
  85.  
  86. \ The following words move data to and from the
  87. \ subroutine stack.  Provides quick "storage."
  88. \ >SR and SR> must be balanced within a word.
  89. CODE >SR  ( n -- )
  90. \ Quick storage ("to-sr")
  91.     MOVE.L    (A6)+,-(A7)
  92.     RTS
  93. END-CODE MACH
  94.  
  95. CODE SR>  ( -- n )
  96. \ "from-sr"
  97.     MOVE.L    (A7)+,-(A6)
  98.     RTS
  99. END-CODE MACH
  100.  
  101. CODE SR@  ( -- n )
  102. \ "sr-fetch"
  103.     MOVE.L    (A7),-(A6)
  104.     RTS
  105. END-CODE MACH
  106.  
  107.  
  108. : #Error  ( n -- )
  109. \ Report error number and ABORT.
  110.     BASE @  SWAP  DECIMAL
  111.     CR ." Trap compiler error #" <# # # # # #> TYPE
  112.     BASE !  ABORT ;
  113.  
  114. GLOBAL
  115. : (:TRAP)  ( trapWord <name> -- )
  116. \ Creates a trap instance and defines the run-time
  117. \ (with DOES>).  Also does a little error checking.
  118.     DEPTH
  119.     IF
  120.         $F000 AND  $A000 =
  121.         IF
  122.             CREATE IMMEDIATE
  123.             DOES>
  124.                 \ Must precede with TOOLBOX
  125.                 0100 #Error
  126.         THEN
  127.     THEN
  128.     \ Missing or incorrect trap word.
  129.     0010 #Error ;
  130.  
  131. : UpCase  ( char --  'char )
  132.     >SR
  133.     SR@    ( char) ASCII `  >
  134.     SR@    ( char) ASCII {  <  AND  ( -1 or 0 )
  135.     -32 AND  SR> + ;
  136.  
  137. CODE $Member  ( char addr -- f )
  138. \ Returns TRUE if char is a member of the counted
  139. \ string at addr, otherwise false.
  140.     MOVEA.L    (A6)+,A0
  141.     MOVE.L    (A6)+,D0
  142.     MOVEQ.L    #TRUE,D2    \ default result
  143.     MOVEQ.L    #0,D1
  144.     MOVE.B    (A0)+,D1    \ character count
  145.     SUBQ.B    #1,D1
  146.     BMI.S    @20
  147. @10    CMP.B    (A0)+,D0
  148.     DBEQ    D1,@10
  149.     BEQ.S    @30
  150. @20    MOVEQ.L    #FALSE,D2
  151. @30    MOVE.L    D2,-(A6)
  152.     RTS
  153. END-CODE
  154.  
  155. CODE SkipBL  ( addr -- addr' )
  156. \ Starting at addr, returns addr of
  157. \ first non-blank character (an ascii
  158. \ blank=#32).  Note that addr
  159. \ should point to a character, NOT
  160. \ a string count.
  161.     MOVEA.L    (A6)+,A0
  162.     MOVEQ.L    #BL,D0
  163. @10    CMP.B    (A0),D0
  164.     BNE.S    @20
  165.     ADDQ.L    #1,A0
  166.     BRA.S    @10
  167. @20    MOVE.L    A0,-(A6)
  168.     RTS
  169. END-CODE
  170.  
  171. CODE CharScan  ( addr c -- addr' )
  172. \ Given the counted string at addr,
  173. \ return a pointer to the first occurrence
  174. \ of character c, or return NIL (zero) if
  175. \ character is not in string. 
  176.     MOVE.L    (A6)+,D0
  177.     MOVEA.L    (A6)+,A0
  178.     MOVEQ.L    #0,D1
  179.     MOVE.B    (A0)+,D1    \ count
  180.     SUBQ.B    #1,D1
  181.     BMI.S    @20
  182. @10    CMP.B    (A0)+,D0
  183.     DBEQ    D1,@10
  184.     BNE.S    @20
  185.     SUBQ.L    #1,A0
  186.     MOVE.L    A0,-(A6)
  187.     RTS
  188. @20    CLR.L    -(A6)
  189.     RTS
  190. END-CODE
  191.     
  192. : SValid  ( char -- f )
  193. \ Returns true is char is an L, W or B.
  194.     " LWBlwb" $Member ;
  195.  
  196. : PValid ( char -- f )
  197. \ Returns true if char is an L, W, B, D, or A.
  198.     " LWBDAlwbda" $Member ;
  199.  
  200. : NValid  ( char -- f )
  201. \ Returns true if char is 0..7
  202.     " 01234567" $Member ;
  203.  
  204. : RValid  ( addr -- f )
  205. \ Check for valid "n.s" sequence where
  206. \ n is 0..7, and s is L, W, or B.
  207.     >SR
  208.     SR@ ( addr)        C@ NValid        ( flag)
  209.     SR@ ( addr) 1+    C@  ASCII .  =    ( flag)  AND
  210.     SR> ( addr) 2+    C@  SValid        ( flag)  AND ;
  211.  
  212. : VerifyOutput  {  addrLimit addrOut | char numOut -- numOut  }
  213. \ Verifies and counts the number of outputs.
  214.     1  +> addrOut  0  -> numOut
  215.     BEGIN
  216.         addrOut SkipBL  -> addrOut
  217.         addrLimit addrOut >
  218.     WHILE
  219.         addrOut C@  -> char
  220.         char  PValid
  221.         IF
  222.             char " LWBlwb" $Member
  223.             IF
  224.                 1  +> addrOut  1  +> numOut
  225.             ELSE
  226.                 \ must be D or A
  227.                 addrOut 1+  RValid
  228.                 IF
  229.                     4  +> addrOut  1  +> numOut
  230.                 ELSE
  231.                     \ Input must be in form of "Dn.s" or "An.s"
  232.                     \ where n is 0..7 and s is L, W, or B.
  233.                     0020 #Error
  234.                 THEN
  235.             THEN
  236.         ELSE
  237.             \ Character stream must begin with L, W, B, D, or A.
  238.             0030 #Error
  239.         THEN
  240.     REPEAT
  241.     numOut ;
  242.  
  243. : VerifyInput  {  addrLimit addrIn | char numIn addrOut -- numIn addrOut  }
  244. \ Verifies and counts the number of inputs.  addrOut will be zero if
  245. \ there is no output, otherwise addrOut points to ending dash (-).
  246.     0  -> numIn  0  -> addrOut
  247.     1  +> addrIn
  248.     BEGIN
  249.         addrIn  SkipBL  -> addrIn
  250.         addrLimit addrIn >
  251.     WHILE
  252.         addrIn C@  -> char
  253.         char  PValid
  254.         IF
  255.             char " LWBlwb" $Member
  256.             IF
  257.                 1  +> addrIn  1  +> numIn
  258.             ELSE
  259.                 \ must be D or A
  260.                 addrIn 1+  RValid
  261.                 IF
  262.                     4  +> addrIn  1  +> numIn
  263.                 ELSE
  264.                     \ Input must be in form of "Dn.s" or "An.s"
  265.                     \ where n is 0..7 and s is L, W, or B.
  266.                     0040 #Error
  267.                 THEN
  268.             THEN
  269.         ELSE
  270.             char ASCII -  =
  271.             IF
  272.                 BEGIN
  273.                     \ scan for more -'s
  274.                     addrIn 1+  C@  ASCII -  =
  275.                 WHILE
  276.                     1  +> addrIn
  277.                 REPEAT
  278.                 addrIn  -> addrOut 
  279.                 addrLimit  -> addrIn        \ force exit of WHILE loop
  280.             ELSE
  281.                 \ Input must be L, W, B, D, A, or -
  282.                 0050 #Error
  283.             THEN
  284.         THEN
  285.     REPEAT
  286.     numIn addrOut ;
  287.  
  288. : VerifyParams  {  | addrIn addrOut addrLimit numIn numOut --
  289.                      addrIn addrOut numIn numOut  }
  290. \ Verifies and counts the number of inputs and outputs.
  291.     0  -> numOut   0  -> numIn   0  -> addrOut
  292.  
  293.     \ Parse to closing parenthesis.
  294.     ASCII ) WORD  -> addrIn
  295.     addrIn C@ 1+  addrIn +  -> addrLimit
  296.     addrIn ASCII (  CharScan  ?DUP
  297.     IF
  298.         \ skip to optional left parenthesis.
  299.         -> addrIn
  300.     THEN
  301.     addrLimit addrIn VerifyInput  -> addrOut  -> numIn
  302.     addrOut
  303.     IF
  304.         addrLimit addrOut VerifyOutput  -> numOut
  305.     THEN
  306.     addrIn 1+  addrOut 1+  numIn numOut ;
  307.  
  308. : RegInput  { offset mode addrIn | dst reg size --  }
  309. \ Compiles an input, moving from stack into register.
  310. \ Mode contains either D or A.
  311.     mode  ASCII A  =  1 AND  -> mode
  312.     addrIn C@  ASCII 0 -  -> reg
  313.     addrIn 2+ C@  -> size
  314.  
  315.     \ Create destination effective address (<ea>).
  316.     mode 6 SHIFT  reg 9 SHIFT  OR  -> dst
  317.     offset 0=
  318.     IF
  319.         \ Although we compile a move into register D0
  320.         \ (a general case), we patch the instruction
  321.         \ with a new destination so that we can move
  322.         \ into any register (i.e. use the dst <ea>).
  323.         [ MOVE.L  (A6)+,D0    AsmWord2 ]
  324.         DstMask AND  dst OR
  325.     ELSE
  326.         size " WBwb" $Member
  327.         IF
  328.             2  +> offset
  329.             [ MOVE.W  0(A6),D0    AsmWord4 ]
  330.         ELSE
  331.             [ MOVE.L  0(A6),D0    AsmWord4 ]
  332.         THEN
  333.         DstMask AND  dst OR W,
  334.         offset
  335.     THEN  W, ;
  336.  
  337. : RegOutput  {  addrOut mode | reg size --  }
  338. \ Compiles an output, moving from register to stack.
  339. \ Result is sign extended if necessary.
  340. \ Mode contains either D or A.
  341.     mode  ASCII A  =  1 AND  -> mode
  342.     addrOut C@  ASCII 0  -  -> reg
  343.     addrOut 2+  C@ UpCase  -> size
  344.  
  345.     size " WB" $Member  mode 0=  AND
  346.     IF
  347.         \ a data register containing a byte or word
  348.         \ length result, sign extend the result.
  349.         size ASCII B =
  350.         IF
  351.             [ EXT.W  D0        AsmWord2 ]
  352.             reg  OR  W,
  353.         THEN
  354.         [ EXT.L  D0        AsmWord2 ]
  355.         reg  OR  W,
  356.     THEN
  357.     [ MOVE.L  D0,-(A6)    AsmWord2 ]
  358.     SrcMask  AND  reg  mode 3 SHIFT OR  OR  W, ;
  359.  
  360. : (Output)  {  addrOut numOut | size --  }
  361. \ Compiles both stack and register based outputs.
  362.     numOut
  363.     IF
  364.         numOut 0
  365.         DO
  366.             addrOut  SkipBL  -> addrOut
  367.             addrOut C@ UpCase  -> size
  368.             size ASCII L =
  369.             IF
  370.                 [ MOVE.L  (A7)+,-(A6)    AsmWord2 ]  W,
  371.             ELSE
  372.                 size " WB" $Member
  373.                 IF
  374.                     [ MOVEA.W  (A7)+,A0    AsmWord2 ]  W,
  375.                     [ MOVE.L  A0,-(A6)    AsmWord2 ]  W,
  376.                 ELSE
  377.                     \ register based, thus "size" is a
  378.                     \ register type (A or D)
  379.                     addrOut 1+  size  RegOutput
  380.                     3  +> addrOut
  381.                 THEN
  382.             THEN
  383.             1  +> addrOut
  384.         LOOP
  385.     THEN ;
  386.  
  387. : (Input)  {  addrIn numIn | offset size --  }
  388. \ Compiles both stack and register based inputs.
  389.     numIn
  390.     IF
  391.         numIn 0
  392.         DO
  393.             numIn I -  1-  4*  -> offset
  394.             addrIn  SkipBL  -> addrIn 
  395.             addrIn C@  UpCase  -> size
  396.             size  ASCII L  =
  397.             IF
  398.                 \ long-word parameter to stack
  399.                 offset 0=
  400.                 IF
  401.                     [ MOVE.L  (A6)+,-(A7)    AsmWord2 ]
  402.                 ELSE
  403.                     [ MOVE.L  0(A6),-(A7)    AsmWord4 ] W,
  404.                     offset
  405.                 THEN  W,
  406.             ELSE
  407.                 size  " WB" $Member
  408.                 IF
  409.                     \ word or byte parameter to stack
  410.                     [ MOVE.W  0(A6),-(A7)    AsmWord4 ] W,
  411.                     2 +> offset  offset W,
  412.                 ELSE
  413.                     \ Register based, thus "size" is a
  414.                     \ register type (A or D)
  415.                     offset  size  addrIn 1+  RegInput
  416.                     3  +> addrIn
  417.                 THEN
  418.             THEN
  419.             1  +> addrIn
  420.         LOOP
  421.     
  422.         \ If ending offset was zero, we popped the last parameter,
  423.         \ thus decrease the numIn stack count by one.
  424.         offset 0=  IF  -1  +> numIn  THEN
  425.  
  426.         numIn
  427.         IF
  428.             \ Drop input parameters.    
  429.             numIn 4*  DUP  8 >
  430.             IF
  431.                 [ ADDA.W  #0,A6        AsmWord4 ] W,
  432.             ELSE
  433.                 %111 AND  9 SHIFT
  434.                 [ ADDQ.L  #8,A6        AsmWord2 ]  OR
  435.             THEN
  436.             W,
  437.         THEN
  438.     THEN ;
  439.  
  440. : ?FuncClr  ( addrOut -- )
  441. \ Clears space on stack (if needed) for function result.
  442.     SkipBL  C@  UpCase
  443.     ( size) DUP  ASCII L  =
  444.     IF
  445.         ( size) DROP
  446.         [ CLR.L  -(A7)    AsmWord2 ] W,
  447.     ELSE
  448.         ( size)  " WB" $Member
  449.         IF
  450.             [ CLR.W  -(A7)    AsmWord2 ] W,
  451.         THEN
  452.     THEN ;
  453.  
  454. \ Note that :TRAP and :PACK defined words produce in-line
  455. \ code (similar to MACH words).  When used with TOOLBOX, they
  456. \ also swap the system stacks (EXG D4,A7) just as a high-level
  457. \ CALL routine would.  If you need the effect of a "(CALL)"
  458. \ routine, use (TOOLBOX) <trap name>
  459.  
  460. : :TRAP  {  trapWord | addrIn addrOut numIn numOut trapBegin --  }
  461. \ Defines a Mac trap call.  Parses parameters from the input
  462. \ character stream.
  463.     trapWord (:TRAP)
  464.     VerifyParams  -> numOut  -> numIn  -> addrOut  -> addrIn
  465.     2 ALLOT  HERE  -> trapBegin
  466.     numOut
  467.     IF
  468.         addrOut ?FuncClr
  469.     THEN
  470.     addrIn numIn (Input)
  471.     trapWord W,
  472.     addrOut numOut (Output)
  473.     [ RTS    AsmWord2 ]  W,
  474.     HERE trapBegin -  trapBegin 2-  W! ;
  475.  
  476. : :PACK  {  trapWord selector | numOut numIn addrOut addrIn packBegin --  }
  477. \ Defines a Mac "pack" trap call.  A "pack" requires a word length
  478. \ selector which is subsequently pushed onto the system stack.
  479. \ Parses parameters from the input character stream.
  480.     trapWord (:TRAP)
  481.     VerifyParams  -> numOut  -> numIn  -> addrOut  -> addrIn
  482.     2 ALLOT  HERE  -> packBegin  
  483.     numOut
  484.     IF
  485.         addrOut ?FuncClr
  486.     THEN
  487.     addrIn numIn (Input)
  488.     \ Compile pack selector value.
  489.     [ MOVE.W  #0,-(A7)    AsmWord4 ] W,  selector W,
  490.     trapWord W,
  491.     addrOut numOut (Output)
  492.     [ RTS    AsmWord2 ]  W,
  493.     HERE packBegin -  packBegin 2- W! ;
  494.  
  495. CODE SwapStack  ( -- )
  496.     EXG        D4,A7
  497.     RTS
  498. END-CODE MACH
  499.  
  500. : CompileTrap  ( addr len -- )
  501. \ Given addr to instructions, compile
  502. \ len-2 bytes of object code (len-2 because
  503. \ it skips the ending RTS).
  504.     OVER >SR  +  SR> 2+
  505.     DO
  506.         I W@  W,
  507.     2 +LOOP ;
  508.  
  509. : VerifyTrap  ( -- addr len flag )
  510. \ Verifies that ticked (') word is a :TRAP or
  511. \ :PACK word (gets len and verifies that
  512. \ an RTS ends the code.
  513.     '  4+  ( addr)  DUP  W@
  514.     ( addr len)  2DUP +  DUP  1 AND  0=
  515.     IF
  516.         W@  [ RTS    AsmWord2 ] =
  517.     ELSE
  518.         \ addr+len produced an odd address.
  519.         DROP  FALSE
  520.     THEN ;
  521.      
  522. : TOOLBOX  ( -- )
  523. \ For :TRAP and :PACK defined traps, use TOOLBOX <trap name>
  524. \ as a substitute for CALL.
  525.     VerifyTrap
  526.     IF
  527.         ( addr len)
  528.         STATE @
  529.         IF
  530.             [ EXG  D4,A7    AsmWord2 ] W,
  531.             ( addr len)  CompileTrap
  532.             [ EXG  D4,A7    AsmWord2 ] W,
  533.         ELSE
  534.             SwapStack
  535.             ( addr len) DROP  2+ EXECUTE
  536.             SwapStack
  537.         THEN
  538.     ELSE
  539.         \ Tried to use TOOLBOX on a non-trap word.
  540.         ( addr len)    \ removed by ABORT
  541.         0200 #Error
  542.     THEN ; IMMEDIATE
  543.  
  544. : (TOOLBOX)  ( -- )
  545. \ For :TRAP and :PACK defined traps, use (TOOLBOX) <trap name>
  546. \ as a substitute for (CALL).
  547.     VerifyTrap
  548.     IF
  549.         ( addr len)
  550.         STATE @
  551.         IF
  552.             ( addr len)  CompileTrap
  553.         ELSE
  554.             ( addr len) DROP  2+ EXECUTE
  555.         THEN
  556.     ELSE
  557.         \ Tried to use (TOOLBOX) on a non-trap word.
  558.         ( addr len)    \ removed by ABORT
  559.         0300 #Error
  560.     THEN ; IMMEDIATE
  561.  
  562.  
  563. \ ===============================================================
  564. \ =========================== Examples ==========================
  565. \ Important note: GetHandleSize and sfGetFile
  566. \ are used ONLY as examples.  These traps ARE
  567. \ compiled CORRECTLY by the current CALL sequence.
  568.  
  569. \ The general syntax for the trap compiler is:
  570. \
  571. \ <trap word> :TRAP <trap name--your choice>  <parameter list>
  572. \
  573. \ The parameter list has the following form:
  574. \     ( <inputs> -- <output> )
  575. \ The right (closing) parenthesis IS required.  The beginning
  576. \ "(" is optional, but should be used because... it looks better.
  577. \ The <input> -- <output> symbols define the parameter size
  578. \ needed for the trap call in question (get that information from
  579. \ Inside Mac).  The trap compiler will then size each parameter,
  580. \ so all input/outputs will be converted automatically to long-words
  581. \ (i.e. you always pass long-words, and results are returned as
  582. \ sign-extended 32-bit values).
  583.  
  584. \ Example of a register-based trap.  Consult Inside Mac
  585. \ for the proper registers.
  586. \ $A025        :TRAP GetHandleSize ( A0.L -- D0.L )
  587.  
  588. \ The value $A025 is the trap word for GetHandleSize.
  589. \ Register-based trap symbols (input/output) are:
  590. \ "An.s"  for address register "n", parameter size is "s".
  591. \ "Dn.s" for data register "n", parameter size is "s".
  592. \ Thus, A0.L means that a long (.L) value is taken
  593. \ from the parameter stack and placed into address register
  594. \ A-zero.  Note that the period (.) between the register number
  595. \ and the parameter size IS required.         
  596.  
  597. \ Here is an example of a stack-based pack call.
  598. \ $A9EA  2    :PACK sfGetFile  ( WWLLWLLL )
  599. \ The value 2 is the pack selector for sfGetFile (see IM I-519).
  600.  
  601. \ Stack-based trap symbols (input/output) are:
  602. \ "L" is a long-word (32-bits), "W" is a word (16-bits),
  603. \ "B" is a byte (value in low-order byte of a word, note that for
  604. \ stack-based parameters a "B" is moved as a word because you must
  605. \ keep stack word aligned.)  Spaces are optional.  If you don't
  606. \ include the dash (--), all characters are considered to be input.
  607. \ It's ok, however, to say ( WWLLWLLL -- ) or ( W W L L W L L L - )
  608.  
  609.  
  610. \ =================== Bug fixes for v2.14 ======================
  611. \ These substitute for mistakes in the v2.14 trap CALL compiler.
  612. \ Explicit CODE-word fixes for these traps are also available in
  613. \ the GEnie RT library file "V2.14 Trap Fixes" 
  614.  
  615. $A05D    :TRAP SwapMMUMode ( D0.B -- D0.B )        \ register based
  616. $A054    :TRAP UprString ( A0.L D0.W -- A0.L )    \    "       "
  617. $AA2B    :TRAP GetNextDevice ( L -- L )            \ stack based
  618. $AA17    :TRAP GetCPixel ( W W L -- )            \   "     "
  619.  
  620.  
  621. \ ==================== Important Note ====================
  622. \ Using the new trap.  Note that you do NOT precede
  623. \ the trap name with CALL.  Traps defined with :TRAP and
  624. \ :PACK use the syntax:  TOOLBOX <trap name> or
  625. \ (TOOLBOX) <trap name>.
  626.  
  627. \ : To32Bit  ( -- n )   1  TOOLBOX SwapMMUMode ;
  628. \ or
  629. \ : UpCase  ( addr -- addr )  COUNT  TOOLBOX UprString ;
  630.  
  631.  
  632. \ ================ Parameter Size Notes =================
  633. \ How do you determine if a parameter is an L, W, or B?
  634. \ Long-word parameters (L's): all VAR's, pointers (Ptr), Handles,
  635. \ records that are longer than 4 bytes, floating point values.
  636. \
  637. \ Word parameters (W's): INTEGER, BOOLEAN, CHAR, Byte
  638. \
  639. \ Byte parameters (B's): 8-bit data does exist, but if you need
  640. \ to pass a byte (by value) to the ROM, it's passed as a word
  641. \ with the value in the low-order byte.  Note that for register
  642. \ based traps, I sign-extend the returned byte to a long-word.
  643. \ This may or may not be what you want, it's a rare situation
  644. \ anyway and would probably never affect your code.
  645.  
  646. \ Read the "fine print" whenever you reference the trap calling
  647. \ sequence in Inside Mac.  This trap compiler MUST use the
  648. \ conventions for assembly language "glue."  Watch out for pack
  649. \ calls (they'll need a selector) and make certain that the
  650. \ Pascal interface doesn't use a different parameter set than
  651. \ does assembly language (this is a common problem in register
  652. \ based trap calls).  Remember, both the standard Mach CALL
  653. \ glue and this trap compiler use assembly language conventions
  654. \ when making trap calls.
  655.  
  656.